package com.manger.common.office.sax;

import com.manger.common.office.sax.parse.SAXSheetHandler;
import com.manger.common.office.sax.parse.SAXSheetRowHandler;
import com.manger.common.office.sax.thread.SAXParseCallable;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.model.SharedStrings;
import org.apache.poi.xssf.model.StylesTable;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.FutureTask;

public class SAXExcelParseExecutor {

   // private SharedStringsTable table;

    private SharedStrings table;

    private StylesTable stylesTable;

    private XSSFReader reader;

    private Class<?>[] classes;

    private SAXSheetRowHandler saxSheetRowHandler = new SAXSheetRowHandler() {
        @Override
        public Object row(String sheetName, Object object, int rowNum) {
            return object;
        }
    };

    private long start = System.currentTimeMillis();

    protected SAXExcelParseExecutor(){

    }

    public SAXExcelParseExecutor listen(SAXSheetRowHandler saxSheetRowHandler){
        this.saxSheetRowHandler = saxSheetRowHandler;
        return this;
    }

    public SAXExcelParseExecutor parse(File file, Class<?>... classes) throws Exception {
        OPCPackage opcPackage = OPCPackage.open(file);
        reader = new XSSFReader(opcPackage);
        table = reader.getSharedStringsTable();
        reader.getStylesTable();
        stylesTable = reader.getStylesTable();

        this.classes = classes;

        return this;
    }

    public  Map<String, List<?>> get() throws Exception{

        Map<String,List<?>> map = new HashMap<>();
        XSSFReader.SheetIterator sheetIterator = (XSSFReader.SheetIterator)reader.getSheetsData();
        int i = 0;
        List list;

        while (sheetIterator.hasNext()){

            InputStream inputStream = sheetIterator.next();
            InputSource is = new InputSource(inputStream);

            list =  parseSheet(is,classes[i],sheetIterator.getSheetName());
            map.put(sheetIterator.getSheetName(),list);

            i++;
        }

        System.out.println("解析耗时：" + ( System.currentTimeMillis() - start ));

        return map;
    }

    public Map<String,List<?>> multiThreadGet() throws Exception{
        Map<String,List<?>> map = new HashMap<>();
        XSSFReader.SheetIterator sheetIterator = (XSSFReader.SheetIterator)reader.getSheetsData();
        int i = 0;
        List<FutureTask<Map<String,List<?>>>> futureTasks = new ArrayList<>();
        while (sheetIterator.hasNext()){
            InputStream inputStream = sheetIterator.next();
            InputSource is = new InputSource(inputStream);
            SAXParseCallable saxParseCallable = new SAXParseCallable(sheetIterator.getSheetName(),is,classes[i],this);
            FutureTask<Map<String,List<?>>> futureTask = new FutureTask(saxParseCallable);
            Thread thread = new Thread(futureTask);
            thread.start();
            futureTasks.add(futureTask);
            i++;
        }

        for (FutureTask<Map<String,List<?>>> futureTask : futureTasks){
            Map<String,List<?>> result = futureTask.get();
            for(String key:result.keySet()){
                map.put(key,result.get(key));
            }
        }

        System.out.println("解析耗时：" + ( System.currentTimeMillis() - start ));

        return map;
    }

    public List<?> parseSheet(InputSource is,Class<?> claz,String sheetName) throws Exception{

        SAXSheetHandler saxSheetHandler = new SAXSheetHandler(sheetName,claz,saxSheetRowHandler);
        XMLReader xmlReader = XMLReaderFactory.createXMLReader();
        XSSFSheetXMLHandler xssfSheetXMLHandler = new XSSFSheetXMLHandler(stylesTable,table,saxSheetHandler,false);

        xmlReader.setContentHandler(xssfSheetXMLHandler);
        xmlReader.parse(is);

        return  saxSheetHandler.get();
    }


    public static void main(String[] args) throws Exception{
        SAXExcelParseExecutor saxExcelParseExecutor = new SAXExcelParseExecutor();
       // saxExcelParseExecutor.parse(new File(""), Material.class).get();
    }

}
